package com.jackstraw.jack_base.datasource.database.parten.config;

import com.jackstraw.jack_base.datasource.common.config.DataSourceConfiguration;
import com.jackstraw.jack_base.datasource.database.parten.entity.DataBaseEntity;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBaseFactory;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBaseProperties;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBasePropertiesEntity;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBaseRouting;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBaseTemplate;
import com.jackstraw.jack_base.datasource.database.parten.entity.bean.DataBaseTemplateCut;
import com.jackstraw.jack_base.datasource.database.parten.exception.BadDataBaseException;
import com.jackstraw.jack_base.util.ObjectUtil;
import com.jackstraw.jack_base.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * 数据库配置类
 *
 * @param <DBE> 具体的数据库连接池配置文件
 * @param <DF>  数据库工厂类
 * @param <DC>  数据库连接池配置类
 */
@Slf4j
@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public abstract class DataBaseConfiguration<DBE extends DataBaseEntity<DBE>,
        DF extends DataBaseFactory<DBE>, DBP extends DataBaseProperties<DBE>,
        DC extends DataBaseConfiguration<DBE, DF, DBP, DC>>
        extends DataSourceConfiguration<DataBaseRouting<DBE, DBP>, DataBasePropertiesEntity<DBE>, DataBaseTemplate<DBE>,
        DF, DataBaseTemplateCut<DBE>, DataBaseProperties<DBE>, DC> {

    public DataBaseConfiguration(ApplicationContext applicationContext, Environment environment) {
        super(applicationContext, environment);
    }


    @Override
    @Bean("databaseProperties")
    @ConfigurationProperties(prefix = "jack.datasource.database")
    public abstract DBP properties();

    @Override
    @Bean("databaseBuildFactory")
    @ConditionalOnBean(name = {"databaseProperties"})
    public abstract DF dataSourceBuildFactory();


    @Override
    @Bean("databaseTemplateCut")
    @ConditionalOnBean(name = {"databaseBuildFactory"})
    public DataBaseTemplateCut<DBE> dataSourceTemplateCut(DF dataSourceBuildFactory) {
        return new DataBaseTemplateCut<>(dataSourceBuildFactory);
    }

    @Override
    @Bean(value = {"databaseRouting"})
    @ConditionalOnBean(name = {"databaseProperties", "databaseBuildFactory", "databaseTemplateCut"})
    public DataBaseRouting<DBE, DBP> routing() {

        DBP properties = SpringUtil.getBean("databaseProperties");
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(properties)) {
            log.error("dataBase配置文件异常");
            throw new BadDataBaseException("037", "dataBase配置文件异常");
        }

        DataBaseTemplateCut dataSourceTemplateCut = SpringUtil.getBean("databaseTemplateCut");
        if (ObjectUtil.ObjectUtilByLang3.isEmpty(dataSourceTemplateCut)) {
            log.error("dataBase切面异常");
            throw new BadDataBaseException("038", "dataBase切面异常");
        }
        DataBaseRouting dataBaseRouting = new DataBaseRouting();
        dataBaseRouting.routing(properties, dataSourceTemplateCut);
        return dataBaseRouting;
    }

    @Primary
    @Bean(value = {"dataSource"})
    @ConditionalOnBean(name = {"databaseRouting"})
    public DataSource dataSource() {
        DataSource dataSource = SpringUtil.getBean("databaseRouting", DataSource.class);
        return dataSource;
    }
}
